<?php
/**
 * Created by PhpStorm.
 * User: lhl
 * Date: 2020/10/21
 * Time: 13:25
 * Features: 检测登录和权限验证
 */

namespace app\adminapiv3\middleware;

use app\common\service\ApiHelper;
use app\common\service\JwtToken;
use think\Db;
use think\Request;

class CheckAuth
{
    //用户id
    private $userId;
    //用户信息
    private $userInfo;
    //响应码
    private $responseCode = [];

    //登录检测忽略控制器 TODO 注意：多级控制器:一级目录和最后一级文件为大驼峰,中间层目录为小驼峰！
    private $_ignoreLoginController = [
        'Install', //安装程序
        'Index', //项目入口
        'Test', //测试控制器
    ];

    //登录检测忽略路由 - 模块/控制器/方法 TODO 注意：多级控制器:一级目录和最后一级文件为大驼峰,中间层目录为小驼峰！
    private $_ignoreLoginRoute = [
        'adminapiv3/Index/isInstall',//是否安装
        'adminapiv3/Login/login',//登录
        'adminapiv3/Login/code',//图形验证码
        'adminapiv3/PlatformManage.ServerAuth/platformAuthInfo',//查询登录页面授权信息
        //...
    ];

    //权限检测忽略控制器  TODO 注意：多级控制器:一级目录和最后一级文件为大驼峰,中间层目录为小驼峰！
    private $_ignoreAuthController = [
        'Install', //安装程序
        'Index', //项目入口
        'PlatformManage.account.ServerPermission', //权限配置控制器
        'Test', //测试控制器
    ];

    //权限检测忽略路由 - 模块/控制器/方法  TODO 注意：多级控制器:一级目录和最后一级文件为大驼峰,中间层目录为小驼峰！
    private $_ignoreAuthRoute = [
        'adminapiv3/Index/isInstall',//是否安装
        'adminapiv3/Login/login',//登录
        'adminapiv3/Login/code',//图形验证码
        'adminapiv3/PlatformManage.ServerAuth/platformAuthInfo',//查询登录页面授权信息
        'adminapiv3/Menu/index',//查询后台菜单
        //...
    ];

    public function handle(Request $request, \Closure $next)
    {
        //状态码
        $this->responseCode = ApiHelper::getCode();
        $request->responseCode = $this->responseCode;
        $controller = $request->controller();
        //真实路由 = 模块/控制器(一级目录和最后一级文件为大驼峰,中间层目录为小驼峰)/方法(小驼峰)
        $route = $request->module().'/'.$controller.'/'.$request->action(true);
        //检测登录
        $this->checkLogin($controller,$route,$request);
        //检测权限
        $this->checkAuth($controller,$route,$request);
        return $next($request);
    }

    /**
     * 检测登录
     * @param string    $controller    当前请求的控制器
     * @param string    $route         当前真实路由：模块/控制器/方法
     * @param object    $request       请求对象
     *
     * @return bool
    */
    protected function checkLogin($controller,$route,Request $request){
        //排除忽略控制器
        if(in_array($controller,$this->_ignoreLoginController)){
            return true;
        }
        //排除忽略路由
        if(in_array($route,$this->_ignoreLoginRoute)){
           return true;
        }

        //解析jwt-token,在请求头中
        $userInfo = JwtToken::checkToken();
        if (!$userInfo) {
            returnErrJson($this->responseCode['not_login_error'], 'TOKEN令牌无效,请重新登录!');
        }

        $params = array(
            'id', 'show_name', 'real_name', 'login_ip'
        );

        foreach ($params as $v){
            if (!isset($userInfo[$v])) {
                returnErrJson($this->responseCode['not_login_error'], 'TOKEN令牌无效,请重新登录!');
            }
        }

        $userIp = $_SERVER['REMOTE_ADDR'];

        if ($userInfo['login_ip'] != $userIp) {
            returnErrJson($this->responseCode['not_login_error'], '身份验证失败,请重新登录!');
        }

        //用于后续权限检测是否已经登录
        $this->userId = $userInfo['id'];//将用户id传入
        $request->user_id = $userInfo['id'];//将用户id传入控制器
        return true;
    }

    /**
     * 检测权限
     * @param string $controller    当前请求的控制器
     * @param string $route         当前真实路由：模块/控制器/方法
     * @param object $request       请求对象
     *
     * @return bool
    */
    protected function checkAuth($controller,$route,Request $request){
        //忽略登录检测的路由,同样也不需要作权限检测
        if(!$this->userId){
            return true;
        }
        //排除忽略控制器
        if(in_array($controller,$this->_ignoreAuthController)){
            return true;
        }
        //排除忽略路由
        if(in_array($route,$this->_ignoreAuthRoute)){
            return true;
        }

        //根据用户id查询用户信息
        $userInfo = Db::name('server_user')
            ->field('id,real_name,show_name,level,host_group_id')
            ->where('id' ,$this->userId)->find();

        if(!$userInfo){
            returnErrJson($this->responseCode['not_login_error'], '用户数据不存在,请重新登录!');
        }

        //查询该账号的角色、权限、菜单信息
        $userInfo = \model('ServerUserGroupMapping')->getRbacInfo($userInfo);
        //进行权限检测
        $auths = $userInfo['rbac']['route'];
        $auths = $auths ? $auths : [];
        if(!in_array($route,$auths)){
            returnErrJson($this->responseCode['not_auth_error'],'您没有权限做此操作!');
        }

        //用于后续权限检测是否已经登录
        $this->userInfo = $userInfo;
        $request->currentLoginUserInfo = $userInfo;//将用户信息传入控制器
        return true;
    }
}